package com.example.demo.game;

import com.example.demo.model.User;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import javax.jws.soap.SOAPBinding;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;

//问题这里为啥会出现线程安全问题
//出现线程安全问题：就是我们对一个队列进行增加和删除的操作，线程1正准备移除玩家1，但是此时线程1还没移除玩家1的同时，线程2给移除了玩家1；
//线程1此时移除的就不是玩家1了，而是玩家1的上一个
@Slf4j
@Component
public class Matcher {

    @Autowired
    OnLineUserManager onLineUserManager;

    @Autowired
    ObjectMapper objectMapper;

    @Autowired
    RoomManager roomManager;
    private Queue<User> normalQueue = new LinkedList<>();
    private Queue<User> highQueue = new LinkedList<>();
    private Queue<User> mostHighQueue = new LinkedList<>();

    public void add(User user){
        if(user.getScore()>=0&&user.getScore()<2000){
            synchronized (normalQueue){
                normalQueue.add(user);
                normalQueue.notify();
            }
            log.info("把玩家："+user.getUsername()+"放入normalQueue");
        }else if(user.getScore()>=2000&&user.getScore()<3000){
            synchronized (highQueue){
                highQueue.add(user);
                highQueue.notify();
            }

            log.info("把玩家："+user.getUsername()+"放入highQueue");
        }else{
            synchronized (mostHighQueue){
                mostHighQueue.add(user);
                mostHighQueue.notify();
            }

            log.info("把玩家："+user.getUsername()+"放入mostHighQueue");
        }
    }

    public void remove(User user){
        if(user.getScore()>=0&&user.getScore()<2000){
            synchronized (normalQueue){
                normalQueue.remove(user);
            }

            log.info("把玩家："+user.getUsername()+"删除normalQueue");
        }else if(user.getScore()>=2000&&user.getScore()<3000){
            synchronized (highQueue){
                highQueue.remove(user);
            }

            log.info("把玩家："+user.getUsername()+"删除highQueue");
        }else{
            synchronized (mostHighQueue){
                mostHighQueue.remove(user);
            }
            log.info("把玩家："+user.getUsername()+"删除mostHighQueue");
        }
    }

    public Matcher(){
        Thread normalThread = new Thread(()->{
              while (true){
                  try {
                      handlerMatch(normalQueue);
                  } catch (IOException | InterruptedException e) {
                      throw new RuntimeException(e);
                  }

              }
        });
        normalThread.start();

        Thread highThread = new Thread(()->{
                  while(true){
                      try {
                          handlerMatch(highQueue);
                      } catch (InterruptedException | IOException e) {
                          throw new RuntimeException(e);
                      }

                  }
        });
        highThread.start();

        Thread mostHighThread = new Thread(()->{
          while (true){
              try {
                  handlerMatch(mostHighQueue);
              } catch (InterruptedException | IOException e) {
                  throw new RuntimeException(e);
              }
          }
        });
        mostHighThread.start();
    }

    private void handlerMatch(Queue<User> matchQueue) throws InterruptedException, IOException {
        synchronized (matchQueue) {
            //检测队列元素个数
            while (matchQueue.size() < 2) {      //玩家数小于2
                matchQueue.wait();
            }
            User player1 = matchQueue.poll();
            User player2 = matchQueue.poll();
            log.info("玩家1：" + player1.getUsername() + "开始游戏");
            log.info("玩家2：" + player2.getUsername() + "开始游戏");

            //获取玩家会话，为了告诉玩家已经匹配到了

            WebSocketSession session1 = onLineUserManager.getUserSession(player1.getUserId());
            User user = (User) session1.getAttributes().get("userInfo");
           log.info(user.toString());
            WebSocketSession session2 = onLineUserManager.getUserSession(player2.getUserId());
            User user1 = (User) session2.getAttributes().get("userInfo");
            log.info(user1.toString());


            //这里的判定是指我们玩家1和玩家2正常匹配，但是玩家1突然不想玩了，然后就取消匹配了，这时候我们就需要把玩家2重新放回到匹配队列

            //这里可以进行测试
            if (session1 == null) {
                //需要把玩家2重新放回队列
                log.info("要把玩家2" + player2.getUsername() + "重新放回匹配队列");
                matchQueue.add(player2);
                return;
            }
            if (session2 == null) {
                //需要把玩家1重新放回队列
                log.info("要把玩家1" + player1.getUsername() + "重新放回匹配队列");
                matchQueue.add(player1);
                return;
            }
            if (session1 == session2) {
                // 把其中的一个玩家放回匹配队列.
                matchQueue.offer(player1);
                return;
            }
            //TODO 这里是玩家匹配到了，就需要把两个玩家放入一个游戏房间中
            Room room = new Room();
            System.out.println(player1.getUserId()+"     "+player2.getUserId());
            roomManager.put(room, player1.getUserId());
            roomManager.put(room, player2.getUserId());

            //然后我们需要给前端返回响应，我们匹配到玩家了
            log.info("这里匹配到了第一个玩家");
            MatchResponse response1 = new MatchResponse();
            response1.setOk(true);
            response1.setMessage("matchSuccess");
            String json1 = objectMapper.writeValueAsString(response1);
            session1.sendMessage(new TextMessage(json1));

            log.info("这里匹配到了第二个玩家");
            MatchResponse response2 = new MatchResponse();
            response2.setOk(true);
            response2.setMessage("matchSuccess");
            String json2 = objectMapper.writeValueAsString(response2);
            session2.sendMessage(new TextMessage(json2));
            log.info("已经返回了数据了");
        }
    }
}
